<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
		    <form>
		      <input type="text"  v-model="number">
		      <button type="button" v-click="increment">增加</button>
		    </form>
		    <h3 v-bind="number"></h3>
		  </div>
		<!-- 
		作者：呆头呆脑丶
		链接：https://juejin.im/post/5acc17cb51882555745a03f8
		来源：掘金
		著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。 -->
	</body>
	<script type="text/javascript">
		class myVue{
			constructor(options,el,data,methods) {
				this.$options = options
			    this.$el = document.querySelector(options.el);
				this.$data = options.data;
				this.$methods = options.methods;
				this._binding = {};
				this._obverse();
				this._complie(this.$el)
			}
			_obverse(){
				var obj = this.$data;
				var arrK = Object.entries(obj)
				if (typeof value === 'object') {
				  _this._obverse(value);
				}
				for (let [key,value] of arrK) {
					if(obj.hasOwnProperty(key)){
						this._binding[key]={
							 _directives: []
						}
						var binding = this._binding[key];
						Object.defineProperty(this.$data,key,{
							enumerable: true,
							configurable: true,
							get:function(){
								return value
							},
							set:function(newVal){
								if(value != newVal){
									value = newVal;
									binding._directives.forEach(function(item){
										item.update();
									})
								}
							}
						})
					}
				}
			}
			_complie(root){
				var _this = this;
				var nodes = root.children;
				for(var i = 0; i < nodes.length; i++){
					if(nodes[i].children.length){
						_this._complie(nodes[i])
					}
					if(nodes[i].hasAttribute("v-click")){
						nodes[i].onclick=(function(){
							let attr = nodes[i].getAttribute('v-click');
							return _this.$methods[attr].bind(_this.$data)
						})()
					}
					if(nodes[i].hasAttribute("v-model")&& (nodes[i].tagName == 'INPUT' || nodes[i].tagName == 'TEXTAREA')){
						nodes[i].addEventListener('input', (function(key) {  
							let attr = nodes[key].getAttribute('v-model');
							_this._binding[attr]._directives.push(
							new Watch("input",nodes[key],_this,attr,"value")
							)
							return function(){
								_this.$data[attr] =  nodes[key].value;
							}
						})(i))
					}
					if(nodes[i].hasAttribute("v-bind")){
						let attr = nodes[i].getAttribute('v-bind');
						_this._binding[attr]._directives.push(
						new Watch("text",nodes[i],_this,attr,"innerHTML")
						)
					}
				}
			}
			
		};
		class Watch{
			constructor(name, el, vm, exp,attr){
			  this.name = name;         //指令名称，例如文本节点，该值设为"text"
				this.el = el;             //指令对应的DOM元素
				this.vm = vm;             //指令所属myVue实例
				this.exp = exp;           //指令对应的值，本例如"number"
				this.attr = attr;         //绑定的属性值，本例为"innerHTML"
				this.update();
			}
			update(){
				this.el[this.attr]=this.vm.$data[this.exp];
			}
		}
		var app = new myVue({
		      el:'#app',
		      data: {
		        number: 0
		      },
		      methods: {
		        increment: function() {
		          this.number ++;
		        },
		      }
		    });
	</script>
</html>
